﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace TasksModel
{
    [System.Xml.Serialization.XmlRootAttribute(Namespace = "http://mp.tasks.com/2010/")]
    public class TaskList : System.Collections.ObjectModel.ObservableCollection<Task>,
        IComparer<Task>,
        IOrderedEnumerable<Task>
    {
        public void MergeWith(TaskList tl)
        {
            for (int i = 0; i < tl.Count; i++)
            {
                Task t = tl[i];
                if (!t.NoSynch)
                    continue;
                Task found = this.FirstOrDefault(delegate(Task ts)
                    {
                        return ts.ID == t.ID;
                    });
                if (null == found)
                    Append(t);// add missing one
                else
                    if (found.Timestamp < t.Timestamp)
                    {
                        t.Order = found.Order;
                        this[found.Order] = t;// replace with newer one
                        System.Diagnostics.Debug.Assert(IndexOf(t) == t.Order);
                    }
            }
        }

        public int Append(Task t)
        {
            int i = Count;
            t.Order = i;
            Add(t);
            System.Diagnostics.Debug.Assert(IndexOf(t) == i);
            return i;
        }

        public void ReplaceWith(Task from, Task with)
        {
            System.Diagnostics.Debug.Assert(IndexOf(from) == from.Order);
            System.Diagnostics.Debug.Assert(IndexOf(with) == with.Order);
            Move(from.Order, with.Order);
            int i = with.Order;
            with.Order = from.Order;
            from.Order = i;
            System.Diagnostics.Debug.Assert(IndexOf(from) == from.Order);
            System.Diagnostics.Debug.Assert(IndexOf(with) == with.Order);
        }

        public void RemoveOrderAware(Task t)
        {
            System.Diagnostics.Debug.Assert(IndexOf(t) == t.Order);
            base.Remove(t);
            for (int i = t.Order; i < Count; i++)
                this[i].Order = i;
            t.Order = 0;
        }

        public void MoveToTheEnd(Task t)
        {
            MoveTo(t, Count - 1);
        }

        public void MoveTo(Task t, int newIndex)
        {
            System.Diagnostics.Debug.Assert(IndexOf(t) == t.Order);
            Move(t.Order, newIndex);
            for (int i = 0; i < Count; i++)
                this[i].Order = i;
            System.Diagnostics.Debug.Assert(IndexOf(t) == t.Order);
        }

        public bool CheckAuthorUsed(TaskAuthor ta)
        {
            return this.Any(delegate(Task t)
            {
                return t.CreatedBy.ID == ta.ID;
            });
        }

        public bool CheckStatusUsed(TaskStatus ts)
        {
            return this.Any(delegate(Task t)
            {
                return t.Status.ID == ts.ID;
            });
        }

        public bool CheckFlagUsed(TaskFlag tf)
        {
            return this.Any(delegate(Task t)
            {
                TaskFlagList tfl = t.Flags;
                return tfl != null &&
                    tfl.Any(delegate(TaskFlag _tf)
                    {
                        return _tf.ID == tf.ID;
                    });
            });
        }

        public List<Task> FindAll(Func<Task, bool> predicate)
        {
            List<Task> l = new List<Task>(2);
            foreach (Task t in Items)
                if (predicate(t))
                    l.Add(t);
            return l;
        }

        private bool _disallowEvent;

        [System.Diagnostics.DebuggerStepThrough]
        public void SuspendChangedEvents()
        {
            _disallowEvent = true;
        }

        [System.Diagnostics.DebuggerStepThrough]
        public void ResumeChangedEvents()
        {
            _disallowEvent = false;
        }

        protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            if (!_disallowEvent)
                base.OnCollectionChanged(e);
        }

        protected override void OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (!_disallowEvent)
                base.OnPropertyChanged(e);
        }

        public int Compare(Task x, Task y)
        {
            return x.CompareTo(y);
        }

        public IOrderedEnumerable<Task> CreateOrderedEnumerable<TKey>(
            Func<Task, TKey> keySelector, IComparer<TKey> comparer, bool descending)
        {
            // get sort order
            IOrderedEnumerable<Task> o = descending ?
                this.OrderByDescending(keySelector, comparer) :
                this.OrderBy(keySelector, comparer);
            // create list in order
            TaskList res = new TaskList();
            res.SuspendChangedEvents();
            foreach (Task s in o)
                res.Add(s);
            res.ResumeChangedEvents();
            return res;
        }
    }
}